#pragma once
#include <cassert>
#include <iostream>
#include <memory>
#include <mutex>

template <class T> class Singleton
{
   public:
    template <typename... Args> static std::shared_ptr<T> &Init(Args &&... args)
    {
        std::call_once(Singleton<T>::_call_once_flag, std::forward<void(Args && ...)>(&Singleton<T>::init), std::forward<Args>(args)...);

        std::cout << " Init --- " << m_pinstance.use_count()<< std::endl;
        return Singleton<T>::m_pinstance;
    }
    static std::shared_ptr<T> &Get()
    {
        if (!m_pinstance)
            throw std::logic_error("the instance is not init, please initialize the instance first");

        std::cout << " Get --- " << m_pinstance.use_count()<< std::endl;
        return Singleton<T>::m_pinstance;
    }
    template <typename... Args> static std::shared_ptr<T> &Getinstance(Args &&... args)
    {
        if (!m_pinstance)
            std::call_once(Singleton<T>::_call_once_flag, std::forward<void(Args && ...)>(&Singleton<T>::init), std::forward<Args>(args)...);

        std::cout << " Getinstance --- " << m_pinstance.use_count()<< std::endl;
        return Singleton<T>::m_pinstance;
    }

   private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton &o) = delete;
    Singleton &operator=(const Singleton &o) = delete;

    template <typename... Args> static void init(Args &&... args)
    {
        //一个 std::unique_ptr 可以被转化成一个 std::shared_ptr 通过一个特殊的构造函数接收右值。std::unique_ptr 持有的内容将会移动给 std::shared_ptr。
        m_pinstance = std::make_shared<T>(std::forward<Args>(args)...);
    }

   private:
    static std::once_flag _call_once_flag;
    static std::shared_ptr<T> m_pinstance;
};

template <class T> std::shared_ptr<T> Singleton<T>::m_pinstance = nullptr;
template <class T> std::once_flag Singleton<T>::_call_once_flag;
